﻿using Devonline.CloudService.Tencent.Weixin;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Devonline.Identity;

/// <summary>
/// 处理业务系统中的微信认证与登录
/// </summary>
public class WeixinIdentityService
{
    private readonly ILogger<WeixinIdentityService> _logger;
    private readonly HttpSetting _httpSetting;
    private readonly HttpContext _httpContext;
    private readonly HttpRequest _httpRequest;
    private readonly AuthenticationService _authenticationService;
    private readonly AuthorizationService _authorizationService;
    private readonly IServiceProvider _serviceProvider;

    public WeixinIdentityService(
        ILogger<WeixinIdentityService> logger,
        IHttpContextAccessor httpContextAccessor,
        HttpSetting httpSetting,
        AuthenticationService authenticationService,
        AuthorizationService authorizationService,
        IServiceProvider serviceProvider
        )
    {
        ArgumentNullException.ThrowIfNull(httpContextAccessor.HttpContext);
        _logger = logger;
        _httpContext = httpContextAccessor.HttpContext;
        _httpRequest = _httpContext.Request;
        _httpSetting = httpSetting;
        _authenticationService = authenticationService;
        _authorizationService = authorizationService;
        _serviceProvider = serviceProvider;
    }

    /// <summary>
    /// 微信认证, 此方法提供微信小程序等非微信开放平台类似接入方式的微信认证过程
    /// </summary>
    /// <param name="code">认证码</param>
    /// <param name="loginType">登录类型</param>
    /// <returns></returns>
    public async Task AuthorizeAsync(string code, WeixinLoginType loginType = WeixinLoginType.MiniProgram)
    {
        if (string.IsNullOrWhiteSpace(code))
        {
            throw new BadHttpRequestException("获取微信用户信息失败!");
        }

        if (loginType == WeixinLoginType.Other)
        {
            loginType = _httpRequest.GetRequestOption<WeixinLoginType>(nameof(loginType));
        }

        _logger.LogInformation($"Weixin {loginType} user apply for authorize");
        if (loginType == WeixinLoginType.MiniProgram)
        {
            var weixinService = _serviceProvider.GetRequiredService<IMiniProgramService>();
            await weixinService.SessionKeyAuthorizeAsync(code);
        }
        else if (loginType == WeixinLoginType.App || loginType == WeixinLoginType.Website)
        {
            var weixinService = _serviceProvider.GetRequiredService<IOpenPlatformService>();
            var state = _httpRequest.GetRequestOption<string>(CLAIM_TYPE_USER_STATE);
            await weixinService.AuthorizeAsync(code, state);
        }
        else
        {
            var weixinService = _serviceProvider.GetRequiredService<IMediaPlatformService>();
            var state = _httpRequest.GetRequestOption<string>(CLAIM_TYPE_USER_STATE);
            await weixinService.AuthorizeAsync(code, state);
        }

        _logger.LogInformation($"user {_httpContext.GetUserName()} use Weixin {loginType} to authorize");
    }
    /// <summary>
    /// 微信登录, 微信认证的后续步骤
    /// </summary>
    /// <param name="code">认证码</param>
    /// <returns></returns>
    public async Task<LoginResultViewModel> LoginAsync(string? code = default, WeixinLoginType loginType = WeixinLoginType.MiniProgram)
    {
        if (loginType == WeixinLoginType.Other)
        {
            loginType = _httpRequest.GetRequestOption<WeixinLoginType>(nameof(loginType));
        }

        _logger.LogInformation($"Weixin user {_httpContext.GetUserName()} will login!");
        var user = await _authenticationService.WeixinLoginAsync();
        var loginViewModel = new LoginResultViewModel { SecurityLevel = _httpSetting.SecurityLevel, Success = false, UserName = user.UserName! };
        if (user.State == DataState.Draft)
        {
            _logger.LogInformation($"user {user.Id} userName {user.UserName} use Weixin to authorize but have not finish the real name authenticate, will redirect to authenticate phoneNumber");
            if ((loginType == WeixinLoginType.MiniProgram || loginType == WeixinLoginType.Website))
            {
                return new LoginResultViewModel { SecurityLevel = _httpSetting.SecurityLevel, RedirectUri = _authenticationService.GetRedirectUrl(user), Success = false, UserName = user.UserName! };
            }
        }

        _logger.LogInformation($"user {user.Id} userName {user.UserName} use Weixin to authorize and bound phoneNumber, need redirect to business function");

        await _authorizationService.ClearCacheAsync(user.UserName!);
        await _authorizationService.GetUserContextAsync(user.UserName);
        await _authorizationService.AuthorizeAsync();
        loginViewModel.Success = true;
        return loginViewModel;
    }
}